home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / procssng / ccs / ccs-11tl.lha / lbl / xview / guidexv / group.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-14  |  27.0 KB  |  1,219 lines

  1. /*
  2.  * This file is a product of Sun Microsystems, Inc. and is provided for
  3.  * unrestricted use provided that this legend is included on all tape
  4.  * media and as a part of the software program in whole or part.  Users
  5.  * may copy or modify this file without charge, but are not authorized to
  6.  * license or distribute it to anyone else except as part of a product
  7.  * or program developed by the user.
  8.  *
  9.  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  10.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  11.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  12.  *
  13.  * This file is provided with no support and without any obligation on the
  14.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  15.  * modification or enhancement.
  16.  *
  17.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  18.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE
  19.  * OR ANY PART THEREOF.
  20.  *
  21.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  22.  * or profits or other special, indirect and consequential damages, even
  23.  * if Sun has been advised of the possibility of such damages.
  24.  *
  25.  * Sun Microsystems, Inc.
  26.  * 2550 Garcia Avenue
  27.  * Mountain View, California  94043
  28.  */
  29.  
  30. #ifndef lint
  31. static char    sccsid[] = "@(#)group.c    2.27 91/10/15 Copyright 1991 Sun Microsystems";
  32. #endif
  33.  
  34. /*
  35.  * Routines for relative layout support through groups
  36.  */
  37.  
  38. #include    "group_impl.h"
  39.  
  40. static    void    layout_none();
  41. static    void    layout_row();
  42. static    void    layout_col();
  43. static    void    layout_rowcol();
  44.  
  45. static    void        group_set_xy();
  46. static    void        group_set_members();
  47. static    Rect        *get_rect_for_group();
  48. static    Group_public    *get_parent_group();
  49. static    void        get_compass_point();
  50. static    void        get_rowcol_info();
  51. static    int        get_value_x();
  52. static    void        place_cell();
  53.  
  54. /*
  55.  * Package initialization, called on xv_create
  56.  */
  57. /*ARGSUSED*/
  58. Pkg_private int
  59. #ifdef __STDC__
  60. group_init(Xv_opaque owner, Group_public *group_public, Attr_avlist avlist)
  61. #else
  62. group_init(owner, group_public, avlist)
  63.     Xv_opaque    owner;
  64.     Group_public    *group_public;
  65.     Attr_avlist    avlist;
  66. #endif
  67. {
  68.     Group_private    *group_private = xv_alloc(Group_private);
  69.  
  70.     if (!group_private)
  71.         return XV_ERROR;
  72.  
  73.     group_public->private_data = (Xv_opaque)group_private;
  74.     group_private->public_self = (Xv_opaque)group_public;
  75.  
  76.     /*
  77.      * Initialize the defaults for certain values
  78.      */
  79.     group_private->group_type = GROUP_NONE;
  80.     group_private->hspacing = 10;
  81.     group_private->vspacing = 10;
  82.     group_private->row_alignment = GROUP_TOP_EDGES;
  83.     group_private->col_alignment = GROUP_LEFT_EDGES;
  84.     group_private->reference_point = GROUP_NORTHWEST;
  85.     group_private->hoffset = 10;
  86.     group_private->voffset = 10;
  87.     group_private->flags |= (SHOWING|LAYOUT);
  88.  
  89.     return XV_OK;
  90. }
  91.  
  92. /*
  93.  * Package set function, called on xv_set
  94.  */
  95. Pkg_private Xv_opaque
  96. #ifdef __STDC__
  97. group_set(Group_public *group_public, Attr_avlist avlist)
  98. #else
  99. group_set(group_public, avlist)
  100.     Group_public    *group_public;
  101.     Attr_avlist    avlist;
  102. #endif
  103. {
  104.     int        i;
  105.     int        x;
  106.     int        x_changed = FALSE;
  107.     int        y;
  108.     int        y_changed = FALSE;
  109.     int        replaced;
  110.     int        need_layout = FALSE;
  111.     int        initial_position = FALSE;
  112.     Xv_opaque    old, new;
  113.     Attr_attribute    *attrs;
  114.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  115.  
  116.     for (attrs = avlist; *attrs; attrs = attr_next(attrs)) {
  117.         switch ((int) attrs[0]) {
  118.         case XV_X:
  119.             x = (int)attrs[1];
  120.             x_changed = TRUE;
  121.             if (!(group_private->flags & CREATED)) {
  122.                 group_private->initial_x = x;
  123.                 group_private->group_rect.r_left = x;
  124.             }
  125.             ATTR_CONSUME(attrs[0]);
  126.             break;
  127.  
  128.         case XV_Y:
  129.             y = (int)attrs[1];
  130.             y_changed = TRUE;
  131.             if (!(group_private->flags & CREATED)) {
  132.                 group_private->initial_y = y;
  133.                 group_private->group_rect.r_top = y;
  134.             }
  135.             ATTR_CONSUME(attrs[0]);
  136.             break;
  137.  
  138.         case PANEL_VALUE_X:
  139.             x = group_private->group_rect.r_left + 
  140.                 ((int)attrs[1] - group_private->value_rect.r_left);
  141.             x_changed = TRUE;
  142.             ATTR_CONSUME(attrs[0]);
  143.             break;
  144.             
  145.         case XV_SHOW:
  146.             for (i = 0; group_private->members[i]; i++) {
  147.                 xv_set(group_private->members[i],
  148.                     XV_SHOW, attrs[1], NULL);
  149.             }
  150.             if ((int)attrs[1])
  151.                 group_private->flags |= SHOWING;
  152.             else
  153.                 group_private->flags &= ~SHOWING;
  154.             break;
  155.  
  156.         case PANEL_INACTIVE:
  157.             for (i = 0; group_private->members[i]; i++) {
  158.                 xv_set(group_private->members[i],
  159.                     PANEL_INACTIVE, (int)attrs[1], NULL);
  160.             }
  161.             if ((int)attrs[1])
  162.                 group_private->flags |= INACTIVE;
  163.             else
  164.                 group_private->flags &= ~INACTIVE;
  165.             break;
  166.  
  167.         case GROUP_TYPE:
  168.             need_layout = TRUE;
  169.             group_private->group_type = (GROUP_TYPES)attrs[1];
  170.             break;
  171.  
  172.         case GROUP_ROWS:
  173.             need_layout = TRUE;
  174.             if ((group_private->rows = (int)attrs[1]) > 0) {
  175.                 group_private->flags |= ROWFIRST;
  176.                 group_private->flags &= ~COLFIRST;
  177.             }
  178.             break;
  179.  
  180.         case GROUP_COLUMNS:
  181.             need_layout = TRUE;
  182.             if ((group_private->cols = (int)attrs[1]) > 0) {
  183.                 group_private->flags |= COLFIRST;
  184.                 group_private->flags &= ~ROWFIRST;
  185.             }
  186.             break;
  187.  
  188.         case GROUP_HORIZONTAL_SPACING:
  189.             need_layout = TRUE;
  190.             group_private->hspacing = (int)attrs[1];
  191.             break;
  192.  
  193.         case GROUP_VERTICAL_SPACING:
  194.             need_layout = TRUE;
  195.             group_private->vspacing = (int)attrs[1];
  196.             break;
  197.  
  198.         case GROUP_ROW_ALIGNMENT:
  199.             need_layout = TRUE;
  200.             group_private->row_alignment = (GROUP_ROW_ALIGNMENTS)attrs[1];
  201.             break;
  202.  
  203.         case GROUP_COLUMN_ALIGNMENT:
  204.             need_layout = TRUE;
  205.             group_private->col_alignment = (GROUP_COLUMN_ALIGNMENTS)attrs[1];
  206.             break;
  207.  
  208.         case GROUP_REPLACE_MEMBER:
  209.             old = (Xv_opaque)attrs[1];
  210.             new = (Xv_opaque)attrs[2];
  211.  
  212.             replaced = FALSE;
  213.  
  214.             for (i = 0; group_private->members[i]; i++) {
  215.                 if (group_private->members[i] == old) {
  216.                     replaced = TRUE;
  217.                     need_layout = TRUE;
  218.                     group_private->members[i] = new;
  219.                 }
  220.             }
  221.             
  222.             if (!replaced)
  223.                 xv_error((Group)group_public,
  224.                     ERROR_STRING, "member not found, not replaced",
  225.                     ERROR_PKG,    GROUP,
  226.                     NULL);
  227.  
  228.             break;
  229.  
  230.         case GROUP_MEMBERS:
  231.             group_set_members(group_public, &attrs[1]);
  232.             need_layout = TRUE;
  233.             break;
  234.  
  235.         case GROUP_MEMBERS_PTR:
  236.             group_set_members(group_public, (Xv_opaque *)attrs[1]);
  237.             need_layout = TRUE;
  238.             break;
  239.  
  240.         case GROUP_LAYOUT:
  241.             if ((int)attrs[1]) {
  242.                 need_layout = TRUE;
  243.                 group_private->flags |= LAYOUT;
  244.             } else
  245.                 group_private->flags &= ~LAYOUT;
  246.             break;
  247.  
  248.         case GROUP_ANCHOR_OBJ:
  249.             need_layout = TRUE;
  250.             group_private->anchor_obj = (Xv_opaque)attrs[1];
  251.             break;
  252.  
  253.         case GROUP_ANCHOR_POINT:
  254.             need_layout = TRUE;
  255.             group_private->anchor_point =
  256.                 (GROUP_COMPASS_POINTS)attrs[1];
  257.             break;
  258.  
  259.         case GROUP_REFERENCE_POINT:
  260.             need_layout = TRUE;
  261.             group_private->reference_point =
  262.                 (GROUP_COMPASS_POINTS)attrs[1];
  263.             break;
  264.  
  265.         case GROUP_HORIZONTAL_OFFSET:
  266.             need_layout = TRUE;
  267.             group_private->hoffset = (int)attrs[1];
  268.             break;
  269.  
  270.         case GROUP_VERTICAL_OFFSET:
  271.             need_layout = TRUE;
  272.             group_private->voffset = (int)attrs[1];
  273.             break;
  274.  
  275.         case XV_END_CREATE:
  276.             need_layout = TRUE;
  277.             initial_position = TRUE;
  278.             group_private->flags |= CREATED;
  279.             break;
  280.  
  281.         default:
  282.             xv_check_bad_attr(GROUP, attrs[0]);
  283.             break;
  284.         }
  285.     }
  286.  
  287.     /*
  288.      * Don't go any further until object has been created
  289.      */
  290.     if (!(group_private->flags & CREATED))
  291.         return (Xv_opaque)XV_OK;
  292.  
  293.     /*
  294.      * If something changed that would change the layout of
  295.      * the group, percolate!
  296.      */
  297.     if (need_layout && (group_private->flags & LAYOUT))
  298.         group_layout((Group)group_public);
  299.  
  300.     /*
  301.      * Check to see if x or y were set, if so we need to move the group.
  302.      */
  303.     if (x_changed || y_changed) {
  304.         if (!x_changed)
  305.             x = group_private->group_rect.r_left;
  306.         if (!y_changed)
  307.             y = group_private->group_rect.r_top;
  308.  
  309.         group_set_xy(group_public, x, y);
  310.     }
  311.     
  312.     /*
  313.      * If this is the first time this group has been positioned,
  314.      * make sure it is placed correctly if it is not anchored.  If
  315.      * it is anchored it was placed correctly earlier.
  316.      */
  317.     if (initial_position && !group_private->anchor_obj) {
  318.         group_set_xy(group_public,
  319.                  group_private->initial_x,
  320.                  group_private->initial_y);
  321.     }
  322.  
  323.     return (Xv_opaque)XV_OK;
  324. }
  325.  
  326. /*
  327.  * Package get function, called on xv_get
  328.  */
  329. /*ARGSUSED*/
  330. Pkg_private Xv_opaque
  331. #ifdef __STDC__
  332. group_get(Group_public *group_public, int *status, Attr_attribute attr,
  333.       Attr_avlist args)
  334. #else
  335. group_get(group_public, status, attr, args)
  336.     Group_public    *group_public;
  337.     int        *status;
  338.     Attr_attribute    attr;
  339.     Attr_avlist    args;
  340. #endif
  341. {
  342.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  343.  
  344.     switch ((int) attr) {
  345.         case XV_X:
  346.             return (Xv_opaque)group_private->group_rect.r_left;
  347.  
  348.         case PANEL_VALUE_X:
  349.             return (Xv_opaque)group_private->value_rect.r_left;
  350.  
  351.         case XV_Y:
  352.             return (Xv_opaque)group_private->group_rect.r_top;
  353.  
  354.         case PANEL_VALUE_Y:
  355.             return (Xv_opaque)group_private->value_rect.r_top;
  356.  
  357.         case XV_WIDTH:
  358.             return (Xv_opaque)group_private->group_rect.r_width;
  359.  
  360.         case XV_HEIGHT:
  361.             return (Xv_opaque)group_private->group_rect.r_height;
  362.  
  363.         case XV_RECT:
  364.             return (Xv_opaque)&(group_private->group_rect);
  365.  
  366.         case XV_SHOW:
  367.             return (Xv_opaque)(group_private->flags & SHOWING);
  368.  
  369.         case PANEL_INACTIVE:
  370.             return (Xv_opaque)(group_private->flags & INACTIVE);
  371.  
  372.         case GROUP_TYPE:
  373.             return (Xv_opaque)group_private->group_type;
  374.  
  375.         case GROUP_ROWS:
  376.             return (Xv_opaque)group_private->rows;
  377.  
  378.         case GROUP_COLUMNS:
  379.             return (Xv_opaque)group_private->cols;
  380.  
  381.         case GROUP_HORIZONTAL_SPACING:
  382.             return (Xv_opaque)group_private->hspacing;
  383.  
  384.         case GROUP_VERTICAL_SPACING:
  385.             return (Xv_opaque)group_private->vspacing;
  386.  
  387.         case GROUP_ROW_ALIGNMENT:
  388.             return (Xv_opaque)group_private->row_alignment;
  389.  
  390.         case GROUP_COLUMN_ALIGNMENT:
  391.             return (Xv_opaque)group_private->col_alignment;
  392.  
  393.         case GROUP_MEMBERS:
  394.             return (Xv_opaque)group_private->members;
  395.  
  396.         case GROUP_LAYOUT:
  397.             return (Xv_opaque)(group_private->flags & LAYOUT);
  398.  
  399.         case GROUP_ANCHOR_OBJ:
  400.             return (Xv_opaque)group_private->anchor_obj;
  401.  
  402.         case GROUP_ANCHOR_POINT:
  403.             return (Xv_opaque)group_private->anchor_point;
  404.  
  405.         case GROUP_REFERENCE_POINT:
  406.             return (Xv_opaque)group_private->reference_point;
  407.  
  408.         case GROUP_HORIZONTAL_OFFSET:
  409.             return (Xv_opaque)group_private->hoffset;
  410.  
  411.         case GROUP_VERTICAL_OFFSET:
  412.             return (Xv_opaque)group_private->voffset;
  413.  
  414.         case GROUP_PARENT:
  415.             return (Xv_opaque)get_parent_group(group_public);
  416.  
  417.         default:
  418.             if (xv_check_bad_attr(GROUP, attr) == XV_ERROR)
  419.                 *status = XV_ERROR;
  420.             break;
  421.     }
  422.  
  423.     return (Xv_opaque)XV_OK;
  424. }
  425.  
  426. /*
  427.  * Package destroy function, called on xv_destroy
  428.  */
  429. Pkg_private int
  430. #ifdef __STDC__
  431. group_destroy(Group_public *group_public, Destroy_status status)
  432. #else
  433. group_destroy(group_public, status)
  434.     Group_public    *group_public;
  435.     Destroy_status    status;
  436. #endif
  437. {
  438.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  439.  
  440.     if (status == DESTROY_CLEANUP)
  441.     {
  442.         /*
  443.          * Mark all members free of this group, then free up
  444.          * space allocated for members list.
  445.          */
  446.         if (group_private->members)
  447.         {
  448.             /*
  449.              * MOOSE - we could only do this if we could tell
  450.              * whether the XView handle is still valid...
  451.              *
  452.             for (i = 0; group_private->members[i]; i++)
  453.                 xv_set(group_private->members[i],
  454.                     XV_KEY_DATA, GROUP_PARENT, NULL, NULL);
  455.              */
  456.  
  457.             xv_free(group_private->members);
  458.         }
  459.  
  460.         xv_free(group_private);
  461.     }
  462.  
  463.     return XV_OK;
  464. }
  465.  
  466. /*
  467.  * Layout a group according to it's constraints
  468.  */
  469. void
  470. #ifdef __STDC__
  471. group_layout(Group group_public)
  472. #else
  473. group_layout(group_public)
  474.     Group    group_public;
  475. #endif
  476. {
  477.     Rect        *r;
  478.     Group_public    *parent;
  479.     Group_private    *group_private;
  480.  
  481.     if (!group_public)
  482.         return;
  483.  
  484.     group_private = GROUP_PRIVATE(group_public);
  485.  
  486.     if (!group_private || !group_private->members)
  487.         return;
  488.  
  489.     switch (group_private->group_type) {
  490.     case GROUP_NONE:
  491.         layout_none(group_public);
  492.         break;
  493.     case GROUP_ROW:
  494.         layout_row(group_public);
  495.         break;
  496.     case GROUP_COLUMN:
  497.         layout_col(group_public);
  498.         break;
  499.     case GROUP_ROWCOLUMN:
  500.         layout_rowcol(group_public);
  501.         break;
  502.     default:
  503.         break;
  504.     }
  505.  
  506.     /*
  507.      * Update x/y/width/height for this group, values may have changed
  508.      */
  509.     r = get_rect_for_group(group_public);
  510.     group_private->group_rect.r_left = r->r_left;
  511.     group_private->group_rect.r_top = r->r_top;
  512.     group_private->group_rect.r_width = r->r_width;
  513.     group_private->group_rect.r_height = r->r_height;
  514.  
  515.     if (group_private->members) {
  516.         group_private->value_rect.r_left = 
  517.             (int)xv_get(group_private->members[0], PANEL_VALUE_X);
  518.         group_private->value_rect.r_top = 
  519.             (int)xv_get(group_private->members[0], PANEL_VALUE_Y);
  520.     } else {
  521.         group_private->value_rect.r_left = group_private->group_rect.r_left;
  522.         group_private->value_rect.r_top = group_private->group_rect.r_top;
  523.     }
  524.  
  525.     /*
  526.      * If this group belongs to a parent group, we need to recurse
  527.      * upwards and layout the parent group now.
  528.      *
  529.      * Otherwise, if this group is anchored, place it relative to anchor
  530.      */
  531.     if (parent = get_parent_group(group_public))
  532.         group_layout((Group)parent);
  533.     else if (group_private->anchor_obj)
  534.         group_anchor((Group)group_public);
  535. }
  536.  
  537. /*
  538.  * Allocate space for an array of Xv_opaques to store new members.
  539.  */
  540. static void
  541. #ifdef __STDC__
  542. group_set_members(Group_public *group_public, Xv_opaque *members)
  543. #else
  544. group_set_members(group_public, members)
  545.     Group_public    *group_public;
  546.     Xv_opaque    *members;
  547. #endif
  548. {
  549.     int        i;
  550.     int        num;
  551.     Xv_opaque    *xvptr = members;
  552.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  553.  
  554.     /*
  555.      * Free up space from old members list
  556.      */
  557.     if (group_private->members)
  558.         xv_free(group_private->members);
  559.  
  560.     if (!members)
  561.     {
  562.         group_private->members = NULL;
  563.         return;
  564.     }
  565.  
  566.     /*
  567.      * Count number of new members
  568.      */
  569.     for (num = 0; *xvptr++; num++)
  570.         ;
  571.  
  572.     /*
  573.      * Allocate space for new members list.  Should use xv_alloc_n
  574.      * here, but it was incorrect in V2 and we want this package
  575.      * to stay portable back to V2.
  576.      */
  577.     group_private->members = (Xv_opaque *)calloc(num+1, sizeof(Xv_opaque));
  578.  
  579.     /*
  580.      * Walk through list and store members, mark each
  581.      * new member in this group.
  582.      */
  583.     for (i = 0; i < num; i++)
  584.     {
  585.         group_private->members[i] = members[i];
  586.         xv_set(group_private->members[i],
  587.             XV_KEY_DATA, GROUP_PARENT, group_public, NULL);
  588.     }
  589. }
  590.  
  591. /*
  592.  * Move a group to a new (absolute) x/y position
  593.  */
  594. static void
  595. #ifdef __STDC__
  596. group_set_xy(Group_public *group_public, int x, int y)
  597. #else
  598. group_set_xy(group_public, x, y)
  599.     Group_public    *group_public;
  600.     int        x;
  601.     int        y;
  602. #endif
  603. {
  604.     int        i;
  605.     Xv_opaque    cur;
  606.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  607.  
  608.     if (!group_private->members)
  609.         return;
  610.  
  611.     for (i = 0; group_private->members[i]; i++)
  612.     {
  613.         cur = group_private->members[i];
  614.         xv_set(cur, XV_X, x + (xv_get(cur, XV_X) - group_private->group_rect.r_left),
  615.                 XV_Y, y + (xv_get(cur, XV_Y) - group_private->group_rect.r_top),
  616.                 NULL);
  617.     }
  618.  
  619.     group_private->group_rect.r_left = x;
  620.     group_private->group_rect.r_top = y;
  621.  
  622.     if (group_private->members) {
  623.         group_private->value_rect.r_left =
  624.             xv_get(group_private->members[0], PANEL_VALUE_X);
  625.         group_private->value_rect.r_top =
  626.             xv_get(group_private->members[0], PANEL_VALUE_X);
  627.     }
  628.     else
  629.     {
  630.         group_private->value_rect.r_left = x;
  631.         group_private->value_rect.r_top = y;
  632.     }
  633. }
  634.  
  635. /*
  636.  * Anchor a group
  637.  */
  638. void
  639. #ifdef __STDC__
  640. group_anchor(Group group_public)
  641. #else
  642. group_anchor(group_public)
  643.     Group    group_public;
  644. #endif
  645. {
  646.     int        new_x;
  647.     int        new_y;
  648.     int        anchor_x;
  649.     int        anchor_y;
  650.     int        ref_x;
  651.     int        ref_y;
  652.     Group_private    *group_private;
  653.  
  654.     if (!group_public)
  655.         return;
  656.  
  657.     group_private = GROUP_PRIVATE(group_public);
  658.  
  659.     if (!group_private || !group_private->anchor_obj)
  660.         return;
  661.  
  662.     get_compass_point(group_private->anchor_obj, group_private->anchor_point,
  663.               &anchor_x, &anchor_y);
  664.     get_compass_point(group_public, group_private->reference_point,
  665.               &ref_x, &ref_y);
  666.  
  667.     if (xv_get(group_private->anchor_obj, XV_OWNER) !=
  668.         xv_get(group_public, XV_OWNER)) {
  669.         anchor_x -= (int)xv_get(group_private->anchor_obj, XV_X);
  670.         anchor_y -= (int)xv_get(group_private->anchor_obj, XV_Y);
  671.     }
  672.  
  673.     new_x = anchor_x + (group_private->group_rect.r_left - ref_x) +
  674.         group_private->hoffset;
  675.     new_y = anchor_y + (group_private->group_rect.r_top - ref_y) +
  676.         group_private->voffset;
  677.  
  678.     group_set_xy(group_public, new_x, new_y);
  679. }
  680.  
  681. /*
  682.  * Layout an as-is group.  Usually means do nothing, check to see
  683.  * if members are anchored first though.
  684.  */
  685. static void
  686. #ifdef __STDC__
  687. layout_none(Group_public *group_public)
  688. #else
  689. layout_none(group_public)
  690.     Group_public    *group_public;
  691. #endif
  692. {
  693.     int        i;
  694.     Xv_opaque    cur;
  695.     Xv_opaque    obj;
  696.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  697.  
  698.     for (i = 0; group_private->members[i]; i++)
  699.     {
  700.         cur = group_private->members[i];
  701.  
  702.         /*
  703.          * Check to see if this member is a group, if so
  704.          * lay it out so it will be anchored correctly.
  705.          */
  706.         XV_OBJECT_TO_STANDARD(cur, "GROUP", obj);
  707.  
  708.         if (obj && (((Xv_base *) obj)->pkg == GROUP))
  709.         {
  710.             group_anchor((Group)cur);
  711.         }
  712.     }
  713.  
  714. }
  715.  
  716. /*
  717.  * Layout a row group
  718.  */
  719. static void
  720. #ifdef __STDC__
  721. layout_row(Group_public *group_public)
  722. #else
  723. layout_row(group_public)
  724.     Group_public    *group_public;
  725. #endif
  726. {
  727.     int        i;
  728.     int        base_y;
  729.     int        new_y;
  730.     Xv_opaque    cur;
  731.     Xv_opaque    prev;
  732.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  733.  
  734.     switch (group_private->row_alignment)
  735.     {
  736.     case GROUP_TOP_EDGES:
  737.         base_y = xv_get(group_private->members[0], XV_Y);
  738.         break;
  739.  
  740.     case GROUP_HORIZONTAL_CENTERS:
  741.         base_y = xv_get(group_private->members[0], XV_Y) + 
  742.             xv_get(group_private->members[0], XV_HEIGHT)/2;
  743.         break;
  744.  
  745.     case GROUP_BOTTOM_EDGES:
  746.         base_y = xv_get(group_private->members[0], XV_Y) + 
  747.             xv_get(group_private->members[0], XV_HEIGHT);
  748.         break;
  749.     }
  750.  
  751.     for (i = 1; group_private->members[i]; i++)
  752.     {
  753.         cur = group_private->members[i];
  754.         prev = group_private->members[i-1];
  755.  
  756.         switch (group_private->row_alignment)
  757.         {
  758.         case GROUP_TOP_EDGES:
  759.             new_y = base_y;
  760.             break;
  761.  
  762.         case GROUP_HORIZONTAL_CENTERS:
  763.             new_y = base_y - xv_get(cur, XV_HEIGHT)/2;
  764.             break;
  765.  
  766.         case GROUP_BOTTOM_EDGES:
  767.             new_y = base_y - xv_get(cur, XV_HEIGHT);
  768.             break;
  769.         }
  770.  
  771.         xv_set(cur, XV_X, xv_get(prev, XV_X) +
  772.                   xv_get(prev, XV_WIDTH) +
  773.                   group_private->hspacing,
  774.                 XV_Y, new_y,
  775.                 NULL);
  776.     }
  777. }
  778.  
  779. /*
  780.  * Layout a column group
  781.  */
  782. static void
  783. #ifdef __STDC__
  784. layout_col(Group_public *group_public)
  785. #else
  786. layout_col(group_public)
  787.     Group_public    *group_public;
  788. #endif
  789. {
  790.     int        i;
  791.     int        new_x;
  792.     int        base_x;
  793.     Xv_opaque    cur;
  794.     Xv_opaque    prev;
  795.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  796.  
  797.     switch (group_private->col_alignment)
  798.     {
  799.     case GROUP_LEFT_EDGES:
  800.         base_x = xv_get(group_private->members[0], XV_X);
  801.         break;
  802.  
  803.     case GROUP_LABELS:
  804.         base_x = xv_get(group_private->members[0], PANEL_VALUE_X);
  805.         break;
  806.  
  807.     case GROUP_VERTICAL_CENTERS:
  808.         base_x = xv_get(group_private->members[0], XV_X) + 
  809.             xv_get(group_private->members[0], XV_WIDTH)/2;
  810.         break;
  811.  
  812.     case GROUP_RIGHT_EDGES:
  813.         base_x = xv_get(group_private->members[0], XV_X) + 
  814.             xv_get(group_private->members[0], XV_WIDTH);
  815.         break;
  816.     }
  817.  
  818.     for (i = 1; group_private->members[i]; i++)
  819.     {
  820.         cur = group_private->members[i];
  821.         prev = group_private->members[i-1];
  822.  
  823.         switch (group_private->col_alignment)
  824.         {
  825.         case GROUP_LEFT_EDGES:
  826.         case GROUP_LABELS:
  827.             new_x = base_x;
  828.             break;
  829.  
  830.         case GROUP_VERTICAL_CENTERS:
  831.             new_x = base_x - xv_get(cur, XV_WIDTH)/2;
  832.             break;
  833.  
  834.         case GROUP_RIGHT_EDGES:
  835.             new_x = base_x - xv_get(cur, XV_WIDTH);
  836.             break;
  837.         }
  838.  
  839.         if (group_private->col_alignment == GROUP_LABELS)
  840.         {
  841.             xv_set(cur, PANEL_VALUE_X, new_x,
  842.                    XV_Y, xv_get(prev, XV_Y) +
  843.                    xv_get(prev, XV_HEIGHT) +
  844.                    group_private->vspacing,
  845.                    NULL);
  846.         }
  847.         else
  848.         {
  849.             xv_set(cur, XV_X, new_x,
  850.                    XV_Y, xv_get(prev, XV_Y) +
  851.                    xv_get(prev, XV_HEIGHT) +
  852.                    group_private->vspacing,
  853.                    NULL);
  854.         }
  855.     }
  856. }
  857.  
  858. /*
  859.  * Layout a row/column group
  860.  */
  861. static void
  862. #ifdef __STDC__
  863. layout_rowcol(Group_public *group_public)
  864. #else
  865. layout_rowcol(group_public)
  866.     Group_public    *group_public;
  867. #endif
  868. {
  869.     int        i;
  870.     int        vx = 0;
  871.     int        current_row = 0;
  872.     int        current_col = 0;
  873.     int        cell_width;
  874.     int        cell_height;
  875.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  876.     Xv_opaque    *members = group_private->members;
  877.  
  878.     get_rowcol_info(group_public, &cell_width, &cell_height);
  879.  
  880.     if (group_private->col_alignment == GROUP_LABELS)
  881.         vx = get_value_x(group_public, 0);
  882.  
  883.     /*
  884.      * Walk through the list, place each object in it's "cell". 
  885.      */
  886.     for (i = 0; members[i]; i++) {
  887.         place_cell(group_public, i, cell_width, cell_height,
  888.                vx, current_row, current_col);
  889.  
  890.         if (group_private->flags & ROWFIRST) {
  891.             if (++current_col >= group_private->cols) {
  892.                 current_row++;
  893.                 current_col = 0;
  894.             }
  895.             if ((group_private->col_alignment == GROUP_LABELS) &&
  896.                 members[i+1])
  897.                 vx = get_value_x(group_public, current_col);
  898.         } else {
  899.             if (++current_row >= group_private->rows) {
  900.                 current_col++;
  901.                 current_row = 0;
  902.                 if ((group_private->col_alignment == GROUP_LABELS) &&
  903.                     members[i+1])
  904.                     vx = get_value_x(group_public, current_col);
  905.             }
  906.         }
  907.     }
  908. }
  909.  
  910. static void
  911. #ifdef __STDC__
  912. get_rowcol_info(Group_public *group_public, int *cell_width, int *cell_height)
  913. #else
  914. get_rowcol_info(group_public, cell_width, cell_height)
  915.     Group_public    *group_public;
  916.     int        *cell_width;
  917.     int        *cell_height;
  918. #endif
  919. {
  920.     int        i;
  921.     int        lw;
  922.     int        vw;
  923.     int        max_lw = -1;
  924.     int        max_vw = -1;
  925.     int        count;
  926.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  927.     Xv_opaque    cur;
  928.  
  929.     /*
  930.      * Calculate rows and column based on number of members
  931.      * and current fill order.
  932.      */
  933.     if ((group_private->rows == 0) && (group_private->cols == 0))
  934.         group_private->rows = 1;
  935.  
  936.     for (count = 0; group_private->members[count]; count++)
  937.         ;
  938.  
  939.     if (group_private->flags & ROWFIRST) {
  940.         group_private->cols = count / group_private->rows;
  941.  
  942.         if (count % group_private->rows)
  943.             group_private->cols++;
  944.     } else {
  945.         group_private->rows = count  / group_private->cols;
  946.  
  947.         if (count % group_private->cols)
  948.             group_private->rows++;
  949.     }
  950.  
  951.     /*
  952.      * Walk through the list, find maximum cell size.  Row/Col
  953.      * groups aligned on labels are special.  The widest item may
  954.      * not determine the cell size.  It is determined by the
  955.      * widest label plus the widest value field, phew.
  956.      */
  957.     *cell_width = -1;
  958.     *cell_height = -1;
  959.  
  960.     if ((group_private->group_type == GROUP_ROWCOLUMN) &&
  961.         (group_private->col_alignment == GROUP_LABELS)) {
  962.         for (i = 0; group_private->members[i]; i++) {
  963.             cur = group_private->members[i];
  964.  
  965.             lw = xv_get(cur, PANEL_VALUE_X) - xv_get(cur, XV_X);
  966.             vw = xv_get(cur, XV_WIDTH) - lw;
  967.  
  968.             if (lw > max_lw)
  969.                 max_lw = lw;
  970.             if (vw > max_vw)
  971.                 max_vw = vw;
  972.             if ((int)xv_get(cur, XV_HEIGHT) > *cell_height)
  973.                 *cell_height = xv_get(cur, XV_HEIGHT);
  974.         }
  975.  
  976.         *cell_width = max_lw + max_vw;
  977.     }
  978.     else
  979.     {
  980.         for (i = 0; group_private->members[i]; i++)
  981.         {
  982.             cur = group_private->members[i];
  983.  
  984.             if ((int)xv_get(cur, XV_WIDTH) > *cell_width)
  985.                 *cell_width = xv_get(cur, XV_WIDTH);
  986.             if ((int)xv_get(cur, XV_HEIGHT) > *cell_height)
  987.                 *cell_height = xv_get(cur, XV_HEIGHT);
  988.         }
  989.     }
  990. }
  991.  
  992. static int
  993. #ifdef __STDC__
  994. get_value_x(Group_public *group_public, int col)
  995. #else
  996. get_value_x(group_public, col)
  997.     Group_public    *group_public;
  998.     int        col;
  999. #endif
  1000. {
  1001.     int        i;
  1002.     int        j;
  1003.     int        tmp;
  1004.     int        start;
  1005.     int        incr;
  1006.     int        vx = -1;
  1007.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  1008.  
  1009.     /*
  1010.      * Walk through the list, find maximum cell size
  1011.      */
  1012.     if (group_private->flags & ROWFIRST)
  1013.     {
  1014.         start = col;
  1015.         incr = group_private->cols;
  1016.     }
  1017.     else
  1018.     {
  1019.         start = col * group_private->rows;
  1020.         incr = 1;
  1021.     }
  1022.  
  1023.     for (j = 0, i = start;
  1024.          group_private->members[i] && j < group_private->rows;
  1025.          i += incr, j++) {
  1026.         tmp = xv_get(group_private->members[i], PANEL_VALUE_X) -
  1027.               xv_get(group_private->members[i], XV_X);
  1028.  
  1029.         if (tmp > vx)
  1030.             vx = tmp;
  1031.     }
  1032.  
  1033.     return vx;
  1034. }
  1035.  
  1036. /*
  1037.  * Place an object correctly inside a cell in a row/col group
  1038.  */
  1039. static void
  1040. #ifdef __STDC__
  1041. place_cell(Group_public *group_public, int i, int cell_width, int cell_height,
  1042.        int vx, int row, int col)
  1043. #else
  1044. place_cell(group_public, i, cell_width, cell_height, vx, row, col)
  1045.     Group_public    *group_public;
  1046.     int        i;
  1047.     int        cell_width;
  1048.     int        cell_height;
  1049.     int        vx;
  1050.     int        row;
  1051.     int        col;
  1052. #endif
  1053. {
  1054.     int        x;
  1055.     int        y;
  1056.     int        cell_x;
  1057.     int        cell_y;
  1058.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  1059.     Xv_opaque    cur = group_private->members[i];
  1060.  
  1061.     /*
  1062.      * Calculate the upper left corner for this cell
  1063.      */
  1064.     cell_x = group_private->group_rect.r_left +
  1065.         col * (cell_width + group_private->hspacing);
  1066.     cell_y = group_private->group_rect.r_top +
  1067.         row * (cell_height + group_private->vspacing);
  1068.  
  1069.     switch (group_private->col_alignment)
  1070.     {
  1071.     case GROUP_LEFT_EDGES:
  1072.         x = cell_x;
  1073.         break;
  1074.     case GROUP_LABELS:
  1075.         x = xv_get(cur, XV_X) +
  1076.             ((cell_x + vx) - xv_get(cur, PANEL_VALUE_X));
  1077.         break;
  1078.     case GROUP_VERTICAL_CENTERS:
  1079.         x = (cell_x + cell_width/2) - xv_get(cur, XV_WIDTH)/2;
  1080.         break;
  1081.     case GROUP_RIGHT_EDGES:
  1082.         x = (cell_x + cell_width) - xv_get(cur, XV_WIDTH);
  1083.         break;
  1084.     }
  1085.  
  1086.     switch (group_private->row_alignment)
  1087.     {
  1088.     case GROUP_TOP_EDGES:
  1089.         y = cell_y;
  1090.         break;
  1091.     case GROUP_HORIZONTAL_CENTERS:
  1092.         y = (cell_y + cell_height/2) - xv_get(cur, XV_HEIGHT)/2;
  1093.         break;
  1094.     case GROUP_BOTTOM_EDGES:
  1095.         y = (cell_y + cell_height) - xv_get(cur, XV_HEIGHT);
  1096.         break;
  1097.     }
  1098.  
  1099.     xv_set(cur, XV_X, x, XV_Y, y, NULL);
  1100. }
  1101.  
  1102. /*
  1103.  * Return the bounding rectangle for a group
  1104.  */
  1105. static Rect *
  1106. #ifdef __STDC__
  1107. get_rect_for_group(Group_public *group_public)
  1108. #else
  1109. get_rect_for_group(group_public)
  1110.     Group_public    *group_public;
  1111. #endif
  1112. {
  1113.     int        i;
  1114.     int        cell_width;
  1115.     int        cell_height;
  1116.     static Rect    bbox;
  1117.     Rect        r;
  1118.     Rect        *r1;
  1119.     Group_private    *group_private = GROUP_PRIVATE(group_public);
  1120.  
  1121.     r = rect_null;
  1122.  
  1123.     if (!group_private->members)
  1124.     {
  1125.         bbox = r;
  1126.         return &bbox;
  1127.     }
  1128.  
  1129.     if (group_private->group_type == GROUP_ROWCOLUMN)
  1130.     {
  1131.         get_rowcol_info(group_public, &cell_width, &cell_height);
  1132.         r.r_left = group_private->group_rect.r_left;
  1133.         r.r_top = group_private->group_rect.r_top;
  1134.         r.r_width = (group_private->cols * cell_width) +
  1135.             ((group_private->cols-1) * group_private->hspacing);
  1136.         r.r_height = (group_private->rows * cell_height) +
  1137.             ((group_private->rows-1) * group_private->vspacing);
  1138.     }
  1139.     else
  1140.     {
  1141.         for (i = 0; group_private->members[i]; i++)
  1142.         {
  1143.             if (r1 = (Rect *)xv_get(group_private->members[i], XV_RECT))
  1144.                 r = rect_bounding(&r, r1);
  1145.         }
  1146.     }
  1147.  
  1148.     bbox = r;
  1149.     return &bbox;
  1150. }
  1151.  
  1152. /*
  1153.  * Return a pointer to a parent group, NULL if none
  1154.  */
  1155. static Group_public *
  1156. #ifdef __STDC__
  1157. get_parent_group(Group_public *group_public)
  1158. #else
  1159. get_parent_group(group_public)
  1160.     Group_public    *group_public;
  1161. #endif
  1162. {
  1163.     return (Group_public *)xv_get((Group)group_public,
  1164.                       XV_KEY_DATA, GROUP_PARENT);
  1165. }
  1166.  
  1167. /*
  1168.  * Calculate the x/y locatiions for a compass point on an object
  1169.  */
  1170. static void
  1171. #ifdef __STDC__
  1172. get_compass_point(Xv_opaque handle, GROUP_COMPASS_POINTS point, int *x, int *y)
  1173. #else
  1174. get_compass_point(handle, point, x, y)
  1175.     Xv_opaque        handle;
  1176.     GROUP_COMPASS_POINTS    point;
  1177.     int            *x;
  1178.     int            *y;
  1179. #endif
  1180. {
  1181.     switch (point)
  1182.     {
  1183.     case GROUP_NORTHWEST:
  1184.     case GROUP_WEST:
  1185.     case GROUP_SOUTHWEST:
  1186.         *x = xv_get(handle, XV_X);
  1187.         break;
  1188.     case GROUP_NORTH:
  1189.     case GROUP_CENTER:
  1190.     case GROUP_SOUTH:
  1191.         *x = xv_get(handle, XV_X) + xv_get(handle, XV_WIDTH)/2;
  1192.         break;
  1193.     case GROUP_NORTHEAST:
  1194.     case GROUP_EAST:
  1195.     case GROUP_SOUTHEAST:
  1196.         *x = xv_get(handle, XV_X) + xv_get(handle, XV_WIDTH);
  1197.         break;
  1198.     }
  1199.  
  1200.     switch (point)
  1201.     {
  1202.     case GROUP_NORTHWEST:
  1203.     case GROUP_NORTH:
  1204.     case GROUP_NORTHEAST:
  1205.         *y = xv_get(handle, XV_Y);
  1206.         break;
  1207.     case GROUP_WEST:
  1208.     case GROUP_CENTER:
  1209.     case GROUP_EAST:
  1210.         *y = xv_get(handle, XV_Y) + xv_get(handle, XV_HEIGHT)/2;
  1211.         break;
  1212.     case GROUP_SOUTHWEST:
  1213.     case GROUP_SOUTH:
  1214.     case GROUP_SOUTHEAST:
  1215.         *y = xv_get(handle, XV_Y) + xv_get(handle, XV_HEIGHT);
  1216.         break;
  1217.     }
  1218. }
  1219.